﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BizUnit;
using Microsoft.Practices.ESB.Resolver;
using System.Xml;
using Microsoft.RuleEngine;

namespace WhiteboardWorks.BizUnitSteps
{

    /// <summary>
    /// The ESBToolkitResolutionContextLoader loads the ESB Resolution object fact and optionally a source document into the context.
    /// The ESB Resolution is a structure used by the ESB toolkit to apply endpoint and mapping dynamic resolution.
    /// </summary>
    /// 
    /// <remarks>
    /// The following shows an example of the Xml representation of this test step.
    /// 
    /// <code escaped="true">
    ///	<ContextLoaderStep assemblyPath="WhiteboardWorks.BizUnitSteps.dll" typeName="WhiteboardWorks.BizUnitSteps.ESBToolkitResolutionContextLoader">
    ///		<FactsContextKey>Facts</FactsContextKey>
    ///		<DocumentType></DocumentType>
    ///		<SourceDocument></SourceDocument>
    ///		<EndPointWCFAction></EndPointWCFAction>
    ///		<ContextWCFAction></ContextWCFAction>
    ///		<CacheTimeout></CacheTimeout>
    ///		<DocumentSpecName></DocumentSpecName>
    ///		<DocumentSpecStrongName></DocumentSpecStrongName>
    ///		<EndpointConfig></EndpointConfig>
    ///		<EpmRRCorrelationTokenField></EpmRRCorrelationTokenField>
    ///		<FixJaxRpc></FixJaxRpc>
    ///		<InboundTransportLocation></InboundTransportLocation>
    ///		<InboundTransportType></InboundTransportType>
    ///		<InterchangeId></InterchangeId>
    ///		<IsRequestResponse></IsRequestResponse>
    ///		<MessageExchangePattern></MessageExchangePattern>
    ///		<MessageType></MessageType>
    ///		<MethodName></MethodName>
    ///		<OutboundTransportCLSID></OutboundTransportCLSID>
    ///		<ReceiveLocationName></ReceiveLocationName>
    ///		<ReceivePortName></ReceivePortName>
    ///		<TargetNamespace></TargetNamespace>
    ///		<TransformType></TransformType>
    ///		<TransportLocation></TransportLocation>
    ///		<TransportNamespace></TransportNamespace>
    ///		<TransportType></TransportType>
    ///		<WindowUser></WindowUser>
    ///	</ContextLoaderStep>
    ///	</code>
    ///	
    ///	</remarks>	
    public class ESBToolkitResolutionContextLoader : IContextLoaderStep
    {
        #region IContextLoaderStep Members

        public void ExecuteContextLoader(System.IO.Stream data, System.Xml.XmlNode contextConfig, Context context)
        {
            context.LogInfo("ESBToolkitResolutionContextLoader [Start]");

            //Facts to be loaded into the context
            object[] facts = null;

            //Source document (if any)
            XmlDocument xmlSourceDocument = null;

            #region Configuration Setup

            //Key to be used to store and retrieve the facts from the Context
            string contextKey = context.ReadConfigAsString(contextConfig, "FactsContextKey", true);

            //Message to be passed as a fact (This message is optional, it is possible to just pass the Resolution Structure)
            string documentType = context.ReadConfigAsString(contextConfig, "DocumentType", true);
            string sourceDocument = context.ReadConfigAsString(contextConfig, "SourceDocument", true);

            Resolution esbResolutionFact = new Resolution();
            esbResolutionFact.Action = context.ReadConfigAsString(contextConfig, "EndPointWCFAction ", true);
            esbResolutionFact.ActionField = context.ReadConfigAsString(contextConfig, "ContextWCFAction", true);
            esbResolutionFact.CacheTimeout = context.ReadConfigAsString(contextConfig, "CacheTimeout", true);
            esbResolutionFact.DocumentSpecNameField = context.ReadConfigAsString(contextConfig, "DocumentSpecName", true);
            esbResolutionFact.DocumentSpecStrongNameField = context.ReadConfigAsString(contextConfig, "DocumentSpecStrongName", true);
            esbResolutionFact.EndpointConfig = context.ReadConfigAsString(contextConfig, "EndpointConfig", true);
            esbResolutionFact.EpmRRCorrelationTokenField = context.ReadConfigAsString(contextConfig, "EpmRRCorrelationToken", true);
            esbResolutionFact.FixJaxRpc = context.ReadConfigAsBool(contextConfig, "FixJaxRpc", true);
            esbResolutionFact.InboundTransportLocationField = context.ReadConfigAsString(contextConfig, "InboundTransportLocation", true);
            esbResolutionFact.InboundTransportTypeField = context.ReadConfigAsString(contextConfig, "InboundTransportType", true);
            esbResolutionFact.InterchangeIdField = context.ReadConfigAsString(contextConfig, "InterchangeId", true);
            esbResolutionFact.IsRequestResponseField = context.ReadConfigAsString(contextConfig, "IsRequestResponse", true);
            esbResolutionFact.MessageExchangePattern = context.ReadConfigAsString(contextConfig, "MessageExchangePattern", true);
            esbResolutionFact.MessageType = context.ReadConfigAsString(contextConfig, "MessageType", true);
            esbResolutionFact.MethodNameField = context.ReadConfigAsString(contextConfig, "MethodName", true);
            esbResolutionFact.OutboundTransportCLSID = context.ReadConfigAsString(contextConfig, "OutboundTransportCLSID", true);
            esbResolutionFact.ReceiveLocationNameField = context.ReadConfigAsString(contextConfig, "ReceiveLocationName", true);
            esbResolutionFact.ReceivePortNameField = context.ReadConfigAsString(contextConfig, "ReceivePortName", true);
            esbResolutionFact.Success = context.ReadConfigAsBool(contextConfig, "Success", true);
            esbResolutionFact.TargetNamespace = context.ReadConfigAsString(contextConfig, "TargetNamespace", true);
            esbResolutionFact.TransformType = context.ReadConfigAsString(contextConfig, "TransformType", true);
            esbResolutionFact.TransportLocation = context.ReadConfigAsString(contextConfig, "TransportLocation", true);
            esbResolutionFact.TransportNamespace = context.ReadConfigAsString(contextConfig, "TransportNamespace", true);
            esbResolutionFact.TransportType = context.ReadConfigAsString(contextConfig, "TransportType", true);
            esbResolutionFact.WindowUserField = context.ReadConfigAsString(contextConfig, "WindowUser", true);

            #endregion

            if (String.IsNullOrEmpty(contextKey)) 
            {
                throw new ApplicationException("FactsContextKey must be provided in order to load the facts into the Context. This key can be used further to retrieve and process the facts accordingly. Check if the 'FactsContextKey' property is set on the ContextLoader step config, and if you are using other steps that use this context information, make sure that all the key values configured match.");            
            }

            //If source document configuration was provided then try to load the document into memory
            if (!String.IsNullOrEmpty(sourceDocument))
            {
                try
                {
                    //Verify if the document type was supplied
                    if (String.IsNullOrEmpty(documentType))
                    {
                        throw new ApplicationException("DocumentType must be provided in order to create the source document fact. Check if the 'DocumentType' property is set on the ContextLoader step config.");
                    }

                    xmlSourceDocument = new XmlDocument();
                    xmlSourceDocument.Load(sourceDocument);

                    TypedXmlDocument typedXmlDocumentFact = new TypedXmlDocument(documentType, xmlSourceDocument);

                    facts = new object[2];
                    facts[0] = esbResolutionFact;
                    facts[1] = typedXmlDocumentFact;
                }
                catch (Exception ex)
                {
                    throw new ApplicationException("ESBToolkitResolverContextLoader could not load the source document. Details: " + ex.Message);
                }
            }
            //if no source document is supplied then just create the ESB Resolution Fact
            else
            {
                facts = new object[1];
                facts[0] = esbResolutionFact;
            }

            try
            {
                //Adds the facts into the context
                context.Add(contextKey, facts, true);
            }
            catch (Exception ex)
            {
                throw new ApplicationException("An error occurred when ESBToolkitResolverContextLoader tried to add the facts into the context. Details: " + ex.Message);
            }

            context.LogInfo("ESBToolkitResolutionContextLoader [End]");
        }

        #endregion
    }
}
